package top.scauwlt.remoting.transport.server;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.IdleStateHandler;
import io.netty.util.concurrent.DefaultEventExecutorGroup;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import top.scauwlt.config.CustomShutDownHook;
import top.scauwlt.config.RpcConfig;
import top.scauwlt.config.RpcServiceConfig;
import top.scauwlt.factory.SingletonFactory;
import top.scauwlt.provider.ServiceProvider;
import top.scauwlt.provider.impl.ServiceProviderImpl;
import top.scauwlt.remoting.dto.RpcMessage;
import top.scauwlt.remoting.transport.codec.RpcMessageDecoder;
import top.scauwlt.remoting.transport.codec.RpcMessageEncoder;
import top.scauwlt.utils.RuntimeUtil;
import top.scauwlt.utils.threadpool.ThreadPoolFactoryUtil;

import java.net.InetAddress;
import java.util.concurrent.TimeUnit;

/**
 * @Author wmm
 * @Date 2022/7/26 16:38
 */
@Slf4j
@Component
public class NettyRpcServer {

    @Autowired
    private ServiceProvider serviceProvider;

    public void registerService(RpcServiceConfig rpcServiceConfig) {
        serviceProvider.publishService(rpcServiceConfig);
    }

    @SneakyThrows
    public void start() {
        CustomShutDownHook.getCustomShutDownHook().clearAll();
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        DefaultEventExecutorGroup serviceHandlerGroup = new DefaultEventExecutorGroup(
                RuntimeUtil.cpus() * 2,
                ThreadPoolFactoryUtil.createThreadFactory("service-handler-group", false));
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    //关闭Nagle算法，降低延迟
                    .childOption(ChannelOption.TCP_NODELAY, true)
                    //开启TCP底层心跳，保持连接
                    .childOption(ChannelOption.SO_KEEPALIVE, true)
                    //表示系统用于临时存放已完成三次握手的请求的队列的最大长度,如果连接建立频繁，服务器处理创建新连接较慢，可以适当调大这个参数
                    //ACCEPT队列
                    .option(ChannelOption.SO_BACKLOG, 128)
                    .handler(new LoggingHandler(LogLevel.INFO))
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel channel) throws Exception {
                            ChannelPipeline pipeline = channel.pipeline();
                            pipeline.addLast(new IdleStateHandler(30, 0, 0, TimeUnit.SECONDS))
                                    .addLast(new RpcMessageEncoder())
                                    .addLast(new RpcMessageDecoder())
                                    .addLast(serviceHandlerGroup, new NettyRpcServerHandler());
                        }
                    });
            String host = InetAddress.getLocalHost().getHostAddress();
            //绑定端口，建立连接
            ChannelFuture channelFuture = b.bind(host, RpcConfig.getInstance().getNettyPort()).sync();
            //阻塞，等待服务器关闭
            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            log.error("occur error when start server: ", e.getMessage());
        } finally {
            log.info("shut down all EventLoopGroup");
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
            serviceHandlerGroup.shutdownGracefully();
        }
    }
}
